﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Media.Media3D;
using System.Windows.Controls;
using System.Windows.Media;
using System.ComponentModel;

namespace Sinacor.Infra.UI.Controls.SmartClient
{
	internal sealed class SinacorViewport2D
	{
		/// <summary>
		/// Seta ou retorna o container do elemento que será adicionado a um ViewPort3D
		/// </summary>
		private Viewport2DVisual3D _viewPort2D;
		public Viewport2DVisual3D ViewPort2D
		{
			get { return _viewPort2D; }
			set { _viewPort2D = value; }
		}

		/// <summary>
		/// Cria um container que irá conter qualquer FrameworkElement definindo posição inicial e escala
		/// </summary>
		/// <param name="element">Elemento a ser adicionado ao container</param>
		/// <param name="totalItems">Total de itens que existirão no container</param>
		/// <param name="offsetX">Posição no eixo X onde o elemento deverá aparecer ao ser criado</param>
		/// <param name="offsetY">Posição no eixo Y onde o elemento deverá aparecer ao ser criado</param>
		public SinacorViewport2D(FrameworkElement element, int totalItems, double offsetX, double offsetY, double xScale, double yScale, bool scaleByItem)
		{
			ViewPort2D = Create2DViewPort(element, totalItems, offsetX, offsetY, xScale, yScale, scaleByItem);
		}

		/// <summary>
		/// Cria e retorna o container contendo um FrameworkElement
		/// </summary>
		/// <param name="element">Elemento a ser adicionado ao container</param>
		/// <param name="totalItems">Total de itens que existirão no container</param>
		/// <param name="offsetX">Posição no eixo X onde o elemento deverá aparecer ao ser criado</param>
		/// <param name="offsetY">Posição no eixo Y onde o elemento deverá aparecer ao ser criado</param>
		/// <returns>O container 3D criado</returns>
		private Viewport2DVisual3D Create2DViewPort(FrameworkElement element, int totalItems, double offsetX, double offsetY, double xScale, double yScale, bool scaleByItem)
		{
			Viewport2DVisual3D viewPort2D = new Viewport2DVisual3D();
			Transform3DGroup transformGroup = new Transform3DGroup();
			TranslateTransform3D translate = new TranslateTransform3D();
			ScaleTransform3D scale = new ScaleTransform3D();
			RotateTransform3D rotate = new RotateTransform3D();

			translate.OffsetX = offsetX;
			translate.OffsetY = offsetY;
			translate.OffsetZ = 0;

			scale.ScaleX = xScale;
			scale.ScaleY = scaleByItem ? yScale * totalItems : yScale;
			scale.ScaleZ = 0.03;
			scale.CenterX = 0;
			scale.CenterY = 0;
			scale.CenterZ = 0;

			AxisAngleRotation3D axisAngleRotation = new AxisAngleRotation3D();
			axisAngleRotation.Angle = 0;
			axisAngleRotation.Axis = new Vector3D(0, 1, 0);
			rotate.Rotation = axisAngleRotation;

			transformGroup.Children.Add(translate);
			transformGroup.Children.Add(scale);
			transformGroup.Children.Add(rotate);

			Point3DCollection positions = new Point3DCollection();
			positions.Add(new Point3D(-1, 1, 0));
			positions.Add(new Point3D(-1, -1, 0));
			positions.Add(new Point3D(1, -1, 0));
			positions.Add(new Point3D(1, 1, 0));

			PointCollection texturePoints = new PointCollection();
			texturePoints.Add(new System.Windows.Point(0, 0));
			texturePoints.Add(new System.Windows.Point(0, 1));
			texturePoints.Add(new System.Windows.Point(1, 1));
			texturePoints.Add(new System.Windows.Point(1, 0));

			Int32Collection triangleIndices = new Int32Collection();
			triangleIndices.Add(0);
			triangleIndices.Add(1);
			triangleIndices.Add(2);
			triangleIndices.Add(0);
			triangleIndices.Add(2);
			triangleIndices.Add(3);

			MeshGeometry3D mesh = new MeshGeometry3D();
			mesh.Positions = positions;
			mesh.TextureCoordinates = texturePoints;
			mesh.TriangleIndices = triangleIndices;

			DiffuseMaterial diffuse = new DiffuseMaterial();
			diffuse.SetValue(System.Windows.Media.Media3D.Viewport2DVisual3D.IsVisualHostMaterialProperty, true);

			viewPort2D.Transform = transformGroup;
			viewPort2D.Geometry = mesh;
			viewPort2D.Material = diffuse;
			viewPort2D.Visual = element;

			return viewPort2D;
		}
	}
}